package com.example.myproject.client;

import java.util.LinkedList;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Panel;

//a grid is a easier to configure gridPanel...
public class myGrid {
	
	//create a new class called cell
	class Cell
	{
		//cell vars
		public Module mod;
		public boolean[] availFor;	
		public int row;
		public int col;
			
		//init the cell to a current row and column
		public Cell(int c, int r)
		{
			//set row and col
			row = r;
			col = c;
			mod = null;
			
			availFor = new boolean[10];
			//init availFor to avail for nothing
			reset();
		}
		
		//if the cell is avail for anything, return treu
		public boolean available()
		{
			
			for(int i = 0; i< 10; i++)
				if(availFor[i]) return true;
			//else return false
			return false;
		}
	
		//reset avail for to everything to false
		public void reset()
		{
			for(int i = 0; i< 10; i++)
				availFor[i] = false;
			mod = null;
		}
	}
	
	//class vars
	protected int plain = 0, dorm =1, sanit = 2, food = 3, gym = 4, canteen = 5, power = 6, control = 7, air = 8, med = 9; 	
	protected static int width = 100, height = 50;	
	//lsit of available cells
	protected LinkedList<Cell> availCells;
	//actual grid
	protected Cell[][] layout;
	//list of unplaced modules (failed to place)
	protected LinkedList<Module> unplaced;	
	
	//constructor for grid
	public myGrid()
	{
		//init the grid to a size of width x height
		layout = new Cell[width][height];
		availCells = new LinkedList<Cell>();
		unplaced = new LinkedList<Module>();
		
		//clear all components, and init cells
		reset();		
	}
	
	//reset clears avail cells, and unplaced cells.  then sets
	//all cells in the grid to a new cell, effectively clearing the old ones
	public void reset()
	{
		//clear lists
		availCells.clear();
		unplaced.clear();
		
		//set cells to new cells
		for(int i =0; i<width; i++)
			for(int j = 0; j<height; j++)
				layout[i][j] = new Cell(i,j);		
	}
	
	
	//check layout will loop through the grid and look for cells that are avail for plain
	//modules, but have nothing in them.  it will then reset that cell and all cells around
	//it to avail for nothing
	public void checkLayout()
	{
		for(int col = 0; col < width; col++)
			for(int row = 0; row< height; row++)
				//if avail for a plain mod, but nothing in it
				if(layout[col][row].availFor[plain] && layout[col][row].mod == null)
				{
					//check left
					if(layout[col-1][row].mod == null && layout[col-1][row].available() && !layout[col-1][row].availFor[plain])
					{
						boolean res = true;
						
						//if there is something in any of the cells around it, dont reset the cell
						if(layout[col-2][row].mod != null && layout[col-2][row].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col-1][row-1].mod != null && layout[col-1][row-1].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col-1][row+1].mod != null && layout[col-1][row+1].mod.getModType().equals("Plain") )
							res = false;
						
						if(res)
							layout[col-1][row].reset();
					}
					//check right
					if(layout[col+1][row].mod == null && layout[col+1][row].available() && !layout[col+1][row].availFor[plain])
					{
						boolean res = true;

						//if there is something in any of the cells around it, dont reset the cell
						if(layout[col+2][row].mod != null && layout[col+2][row].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col+1][row-1].mod != null && layout[col+1][row-1].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col+1][row+1].mod != null && layout[col+1][row+1].mod.getModType().equals("Plain") )
							res = false;
						
						if(res)
							layout[col+1][row].reset();
					}	
					
					//check down
					if(layout[col][row+1].mod == null && layout[col][row+1].available() && !layout[col][row+1].availFor[plain])
					{
						boolean res = true;

						//if there is something in any of the cells around it, dont reset the cell
						if(layout[col-1][row+1].mod != null && layout[col-1][row+1].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col+1][row+1].mod != null && layout[col+1][row+1].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col][row+2].mod != null && layout[col][row+2].mod.getModType().equals("Plain") )
							res = false;
						
						if(res)
						
						layout[col][row+1].reset();
					}	
					
					//check up
					if(layout[col][row-1].mod == null && layout[col][row-1].available() && !layout[col][row-1].availFor[plain])
					{
						boolean res = true;

						//if there is something in any of the cells around it, dont reset the cell
						if(layout[col-1][row-1].mod != null && layout[col-1][row-1].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col+1][row-1].mod != null && layout[col+1][row-1].mod.getModType().equals("Plain"))
							res = false;
						else if(layout[col][row-2].mod != null && layout[col][row-2].mod.getModType().equals("Plain") )
							res = false;
						
						if(res)
						
						layout[col][row-1].reset();
					}	
				}	
	
	//clear lsit of available cells
	availCells.clear();
	//reset the avil cells list
	setAvailCells();
}
	
	//fill empty is the method that will attempt to place any extra modules next to plain
	//modules with nothing around them
	public void fillEmpty()
	{
		//temp row will keep track of the current cell
		int tempRow = 0, tempCol = 0;
		
		//loop through layout 
		for(int col = 0; col < width; col++)
			for(int row = 0; row< height; row++)
				//if it is not empty and is a plain module
				if(layout[col][row].mod != null && layout[col][row].mod.getModType().equals("Plain"))
				{
					//check left
					tempCol = col -1;
					tempRow = row;					
					if(layout[tempCol][tempRow].mod == null)
					{
						//set it available for everything cept plains
						layout[tempCol][tempRow].reset();
						for(int i = 1; i < 10; i++)
							layout[tempCol][tempRow].availFor[i] = true;
						layout[tempCol][tempRow].availFor[gym] = false;
						
						//if there is a airlock ANYWHER near
						if((layout[tempCol-1][tempRow].mod != null && layout[tempCol-1][tempRow].mod.getModType().equals("Airlock") )||
								( layout[tempCol][tempRow+1].mod != null && layout[tempCol][tempRow+1].mod.getModType().equals("Airlock") )||
								( layout[tempCol][tempRow-1].mod != null && layout[tempCol][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Airlock")) )
						{
							//we can't have another airlock or a dorm module
							layout[tempCol][tempRow].availFor[air] = false;
							layout[tempCol][tempRow].availFor[dorm] = false;
						}
						// if there is a sanitation anywhere near
						if((layout[tempCol-1][tempRow].mod != null && layout[tempCol-1][tempRow].mod.getModType().equals("Sanitation") )||
								( layout[tempCol][tempRow+1].mod != null && layout[tempCol][tempRow+1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol][tempRow-1].mod != null && layout[tempCol][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Sanitation")) )
						{
							//we can have a gym, but no caneen of food storage
							layout[tempCol][tempRow].availFor[gym] = true;
							layout[tempCol][tempRow].availFor[food] = false;
							layout[tempCol][tempRow].availFor[canteen] = false;
						}	
					}
					//check right
					tempCol = col +1;
					tempRow = row;					
					if(layout[tempCol][tempRow].mod == null)
					{
						//set it available for everything cept plains
						layout[tempCol][tempRow].reset();
						for(int i = 1; i < 10; i++)
							layout[tempCol][tempRow].availFor[i] = true;
						layout[tempCol][tempRow].availFor[gym] = false;
						
						//any airlocks?
						if(( layout[tempCol+1][tempRow].mod != null && layout[tempCol+1][tempRow].mod.getModType().equals("Airlock") )||
								( layout[tempCol][tempRow+1].mod != null && layout[tempCol][tempRow+1].mod.getModType().equals("Airlock") )||
								( layout[tempCol][tempRow-1].mod != null && layout[tempCol][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Airlock")) )
						{
							//if so, cant be anoher airlock, and cant be a dorm
							layout[tempCol][tempRow].availFor[air] = false;
							layout[tempCol][tempRow].availFor[dorm] = false;
						}
						//any sanits?
						if(( layout[tempCol+1][tempRow].mod != null && layout[tempCol+1][tempRow].mod.getModType().equals("Sanitation") )||
								( layout[tempCol][tempRow+1].mod != null && layout[tempCol][tempRow+1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol][tempRow-1].mod != null && layout[tempCol][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Sanitation")) )
						{
							//we can have a gym, but no canteen or food storage
							layout[tempCol][tempRow].availFor[food] = false;
							layout[tempCol][tempRow].availFor[canteen] = false;
							layout[tempCol][tempRow].availFor[gym] = true;
						}	
					}
										
					//check down					
					tempCol = col;
					tempRow = row+1;					
					if(layout[tempCol][tempRow].mod == null)
					{
						//set it available for everything cept plains
						layout[tempCol][tempRow].reset();
						for(int i = 1; i < 10; i++)
							layout[tempCol][tempRow].availFor[i] = true;
						layout[tempCol][tempRow].availFor[gym] = false;
						
						//any airlocks?
						if((layout[tempCol-1][tempRow].mod != null && layout[tempCol-1][tempRow].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow].mod != null && layout[tempCol+1][tempRow].mod.getModType().equals("Airlock") )||
								( layout[tempCol][tempRow+1].mod != null && layout[tempCol][tempRow+1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Airlock")) )
						{
							//if so, we cant have another airlock, or a dorm module
							layout[tempCol][tempRow].availFor[air] = false;
							layout[tempCol][tempRow].availFor[dorm] = false;
						}
						//any sanits?
						if((layout[tempCol-1][tempRow].mod != null && layout[tempCol-1][tempRow].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow].mod != null && layout[tempCol+1][tempRow].mod.getModType().equals("Sanitation") )||
								( layout[tempCol][tempRow+1].mod != null && layout[tempCol][tempRow+1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Sanitation")) )
						{
							//can't be food storage or a canteen, but can be a gym
							layout[tempCol][tempRow].availFor[food] = false;
							layout[tempCol][tempRow].availFor[canteen] = false;
							layout[tempCol][tempRow].availFor[gym] = true;
						}	
					}
					
					//check up
					tempCol = col;
					tempRow = row-1;					
					if(layout[tempCol][tempRow].mod == null)
					{
						//set it available for everything cept plains and gym
						layout[tempCol][tempRow].reset();
						for(int i = 1; i < 10; i++)
							layout[tempCol][tempRow].availFor[i] = true;
						layout[tempCol][tempRow].availFor[gym] = false;
						
						//any airlocks?
						if((layout[tempCol-1][tempRow].mod != null && layout[tempCol-1][tempRow].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow].mod != null && layout[tempCol+1][tempRow].mod.getModType().equals("Airlock") )||
								( layout[tempCol][tempRow-1].mod != null && layout[tempCol][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Airlock") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Airlock")) )
						{
							//if so, we cant have another airlock or a dorm
							layout[tempCol][tempRow].availFor[air] = false;
							layout[tempCol][tempRow].availFor[dorm] = false;
						}
						//any sanit?
						if((layout[tempCol-1][tempRow].mod != null && layout[tempCol-1][tempRow].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow].mod != null && layout[tempCol+1][tempRow].mod.getModType().equals("Sanitation") )||
								( layout[tempCol][tempRow-1].mod != null && layout[tempCol][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow+1].mod != null && layout[tempCol+1][tempRow+1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow-1].mod != null && layout[tempCol-1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol+1][tempRow-1].mod != null && layout[tempCol+1][tempRow-1].mod.getModType().equals("Sanitation") )||
								( layout[tempCol-1][tempRow+1].mod != null && layout[tempCol-1][tempRow+1].mod.getModType().equals("Sanitation")) )
						{
							//can have food or canteen, but can have a gym
							layout[tempCol][tempRow].availFor[food] = false;
							layout[tempCol][tempRow].availFor[canteen] = false;
							layout[tempCol][tempRow].availFor[gym] = true;
						}	
					}
				}
		
		//clear avail list and reset it with new configuration
		availCells.clear();
		setAvailCells();
		
		//for every module in unplaced, attemp to place everything except dorm and sanit
		for (int i = 0; i< unplaced.size(); i++)
		{
			Module m = unplaced.get(i);
			if(m.getModType().equals("Dormitory") || m.getModType().equals("Sanitation"))
			{
				
			}
			else
			{
				//add the unplaced module, true means add it but dont re-add it to unplaced if you coundn't place it
				add(m, true);
				unplaced.remove(i);
				i--;
			}
		}
		//same as above, but only add dorm and sanit
		for (int i = 0; i< unplaced.size(); i++)
		{
			Module m = unplaced.get(i);
			if(m.getModType().equals("Dormitory") || m.getModType().equals("Sanitation"))
			{
				add(m, true);
				unplaced.remove(i);
				i--;
			}
		}			
	}
	
	//a public add method that hides the "shouldnotPopulateUnplaced" vriable
	public void add(Module mod)
	{		
		add(mod, false);
	}
	
	//add will add a module to a area fit for that module, and shouldNotPopulateUnplaced
	//means that if it is true, dont add the module to unplace list if it couldnt place
	//it anywhere, and false means you SHOULD add it to unplaced
	protected void add(Module mod, boolean shouldNotPopulateUnplaced)
	{
		//weird logic for placed...if this is oringally true, modules never enter the unplaced list
		boolean placed = shouldNotPopulateUnplaced;
		
		
		//the following will check what type the module is, then look in the avilable list
		//for a cell that is available for that type, and place it in the first available cell
		
		if(mod.getModType().equals("Plain"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[plain])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Airlock"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[air])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Food and Water Storage"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[food])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Dormitory"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[dorm])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Sanitation"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[sanit])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Gym"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[gym])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Canteen"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[canteen])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Power"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[power])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		else if(mod.getModType().equals("Control"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[control])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}

		else if(mod.getModType().equals("Medical"))
		{
			for(int i = 0; i<availCells.size(); i++)
			{
				if(availCells.get(i).availFor[med])
				{
					availCells.remove(i).mod = mod;
					placed = true;
					break;
				}
			}
		}
		
		//if placed is false, add the module to unplaced list
		if(!placed)
		{
			unplaced.add(mod);
		}
	}
	
	//loop through grid and look for available cells, if they are available, add them to avilCells
	protected void setAvailCells()
	{
		for(int i = 0; i<height; i++)
			for(int j = 0; j< width;j++)
				if(layout[j][i].available() && layout[j][i].mod == null && !layout[j][i].availFor[plain])
					availCells.add(layout[j][i]);
	}
	
	//converts the grid to a visible panel
	public Panel toPan()
	{
		//create a grid panel
		Grid realGrid = new Grid(height, width);
		for(int i = 0; i<width; i++)
		{
			for(int j = 0; j<height; j++)
			{
				//if the layout has a module,
				if(layout[i][j].mod != null)
					//place it's image into the grid
					realGrid.setWidget(j, i, layout[i][j].mod.getImage());
			}
		}
		
		return realGrid;
	}

	//set all will loop through the layout and move all modules in it to the locations shown by the grid
	public void setAll(){
		for(int r = 0; r<height; r++)
			for(int c = 0; c<width; c++)			
			{
				if(layout[c][r].mod != null)
				{
					//get the module
					Module mod = layout[c][r].mod;
					//set their x and y coords to teh cells col and row
					mod.setTempXY(layout[c][r].col+1, height - (layout[c][r].row+1));
				}
			}
	}
		
}
